/* eslint-disable no-inner-declarations */
import obPlugin from "./scripts/ob.esbuild.mjs";
import { inlineWorkerPlugin } from "@aidenlx/esbuild-plugin-inline-worker";
import { build, context } from "esbuild";
import { lessLoader } from "esbuild-plugin-less";
import { readFile } from "fs/promises";
import { join } from "path";
// import myPackage from "./package.json" assert { type: "json" };
import semverPrerelease from "semver/functions/prerelease.js";
import PostcssPlugin from "./esbuild-postcss.mjs";

const myPackage = JSON.parse(await readFile("./package.json"));
const isPreRelease = semverPrerelease(myPackage.version) !== null;

const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source visit the plugins github repository
*/
`;

const cmExternals = [
  "@codemirror/autocomplete",
  "@codemirror/collab",
  "@codemirror/commands",
  "@codemirror/language",
  "@codemirror/lint",
  "@codemirror/search",
  "@codemirror/state",
  "@codemirror/text",
  "@codemirror/view",
  "@lezer/common",
  "@lezer/lr",
  "@lezer/highlight",
  "@codemirror/closebrackets",
  "@codemirror/comment",
  "@codemirror/fold",
  "@codemirror/gutter",
  "@codemirror/highlight",
  "@codemirror/history",
  "@codemirror/matchbrackets",
  "@codemirror/panel",
  "@codemirror/rangeset",
  "@codemirror/rectangular-selection",
  "@codemirror/stream-parser",
  "@codemirror/tooltip",
];

const isProd = process.env?.BUILD === "production";

const preactCompatPlugin = {
  name: "preact-compat",
  setup(build) {
    const preact = join(process.cwd(), "node_modules", "@preact", "compat");
    build.onResolve({ filter: /^(react-dom|react)$/ }, () => {
      return { path: join(preact, "index.mjs") };
    });
    build.onResolve({ filter: /^react\/jsx-runtime$/ }, () => {
      return { path: join(preact, "jsx-runtime.mjs") };
    });
  },
};

/** @type import("esbuild").BuildOptions */
const baseOpts = {
  bundle: true,
  platform: "node",
  format: "cjs",
  mainFields: ["browser", "module", "main"],
  minify: isProd,
  define: {
    "process.env.NODE_ENV": JSON.stringify(process.env.BUILD ?? ""),
    "process.env.SQL_VERBOSE": JSON.stringify(process.env.SQL_VERBOSE ?? ""),
  },
};

/** @type import("esbuild").BuildOptions */
const opts = {
  ...baseOpts,
  logLevel: process.env.BUILD === "development" ? "info" : "silent",
  external: ["obsidian", "electron", "@electron/remote", ...cmExternals],
  mainFields: ["browser", "module", "main"],
  sourcemap: isProd ? false : "inline",
  loader: {
    ".svg": "text",
    ".ejs": "text",
  },
  entryPoints: ["src/zt-main.ts"],
  banner: { js: banner },
  outfile: "build/main.js",
  tsconfig: "tsconfig.build.json",
  plugins: [
    lessLoader(),
    obPlugin({ beta: isPreRelease }),
    preactCompatPlugin,
    inlineWorkerPlugin({
      buildOptions: async ({ path }, resolve) => ({
        ...baseOpts,
        tsconfig: (
          await resolve(
            path.startsWith("@/worker-web/")
              ? "src/worker-web/tsconfig.json"
              : path.startsWith("@/worker-iframe/")
              ? "src/worker-iframe/tsconfig.json"
              : `${path}/tsconfig`,
            { kind: "require-resolve" }
          )
        ).path,
        target: "es2022",
        platform: path.startsWith("@/worker-iframe/") ? "browser": "node",
        format: path.startsWith("@/worker-iframe/") ? "esm" : "cjs",
        sourcemap: !isProd ? "inline" : false,
      }),
      cachedir: "dist",
      watch: !isProd,
    }),
    PostcssPlugin({}),
  ],
};

if (!isProd) {
  const ctx = await context({ ...opts, logLevel: "error" });
  try {
    await ctx.watch();
  } catch (err) {
    console.error(err);
    await cleanup();
  }
  process.on("SIGINT", cleanup);
  async function cleanup() {
    await ctx.dispose();
    // scheduleOnDisposeCallbacks defer function calls using setTimeout(...,0)
    // so we need to wait a bit before exiting
    // setTimeout(() => process.exit(), 100);
  }
} else {
  await build(opts);
}
